/*
 * Created on 2008-06-05
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package elka.isi.individual;

import elka.isi.gene.AnimalGene;
import org.evolvica.core.AbstractIndividual;

/**
 * @author Zibi
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public abstract class AnimalIndividual extends AbstractIndividual {
	
	protected double huntingScore;
    protected double appetiteScore;
    protected double reproductionScore;
    public static final int RABBIT = 0;
    public static final int WOLF = 1;
    public static final int ROE = 2;
    
    public abstract Class getSpecies_OLD();
    public abstract int getSpecies();

	
    public abstract void evaluate(int rabbitsInPopulation,int roesInPopulation,int wolvesInPopulation);

    /**
     * @return size^2 * muscle

     */
    protected float countStrength()
    {
        AnimalGene gene = (AnimalGene) getGenotype();

        int muscle = gene.getGene(AnimalGene.MUSCLE_GENE);
        int size = gene.getGene(AnimalGene.SIZE_GENE);

        double strength = muscle * size * size;

        /* normalizacja */
        strength = normalize(strength, 1, 100*100*100);
        strength = correctRange("strength", strength);

        return (float) strength;
    }

    /**
     * @return muscle * legs_length^2 * | size - OSS |^2
     */
    protected int countSpeed()
    {
        AnimalGene gene = (AnimalGene) getGenotype();

        int muscle = gene.getGene(AnimalGene.MUSCLE_GENE);
        int legsLength = gene.getGene(AnimalGene.LEGS_LENGTH_GENE);
        int size = gene.getGene(AnimalGene.SIZE_GENE);

        double speed = muscle * legsLength;

        /* normalizacja */
        speed = normalize(speed, 1, 100*100*100);
        speed = correctRange("speed",speed);

        return (int) speed;
    }

    /**
     * @return muscle / (legs_length^2 + size^3)
     */
    protected float countAgility()
    {
        AnimalGene gene = (AnimalGene) getGenotype();

        float muscle = gene.getGene(AnimalGene.MUSCLE_GENE);
        float legsLength = gene.getGene(AnimalGene.LEGS_LENGTH_GENE);
        float size = gene.getGene(AnimalGene.SIZE_GENE);

        double agility = muscle / size;

        /* normalizacja */
        agility = normalize(agility, 0.005, 50);
        agility = correctRange("agility",agility);

        return (float)agility;
    }

    /**
      * @return 2 * eyesigth * size +  hearing + 3 * smell
     */
    protected float countPerceptiveness() {
        AnimalGene gene = (AnimalGene) getGenotype();

        int eyesigth = gene.getGene(AnimalGene.EYESIGTH_GENE);
        int size = gene.getGene(AnimalGene.SIZE_GENE);
        int hearing = gene.getGene(AnimalGene.HEARING_GENE);
        int smell = gene.getGene(AnimalGene.SMELL_GENE);

        double perceptiveness = 2*eyesigth*size + hearing + 3*smell;

        /* normalizacja */
        perceptiveness = normalize(perceptiveness, 6, 20400);
        perceptiveness = correctRange("perspectiveness", perceptiveness);

        return (float) perceptiveness;
    }

    /**
     * @return 2 * speed + 2 * agility +10log(perceptivenes) + 5log(smartness / memory)
     */
    protected double countHuntingScore()
    {
        AnimalGene gene = (AnimalGene) getGenotype();

        float size = gene.getGene(AnimalGene.SIZE_GENE);
        float speed = countSpeed();
        float agility = countAgility();
        float perceptiveness = countPerceptiveness();
        float smartness = gene.getGene(AnimalGene.SMARTNESS_GENE);
        float memory = gene.getGene(AnimalGene.MEMORY_GENE);

        //double hunting = 2*speed + 2*agility + 10*Math.log(perceptiveness) + 5 * Math.log( smartness / memory );
        double hunting = 5*size + speed + agility;

        /* normalizacja */
        hunting = normalize(hunting,  4, 500);
        hunting = correctRange("huntingScore", hunting);

        return hunting;
    }

    
    /**
     * @return size^2 * muscle / metabolism
     */
    protected double countAppetiteScore()
    {
        AnimalGene gene = (AnimalGene) getGenotype();

        double size = gene.getGene(AnimalGene.SIZE_GENE);
        double muscle = gene.getGene(AnimalGene.MUSCLE_GENE);
        double metabolism = gene.getGene(AnimalGene.METABOLISM_GENE);

        double appetite = (2 * size + muscle) / metabolism;
       // appetite = appetite / 20 + 1;

        /* normalizacja */
        appetite = normalize(appetite, 0.01, 100*100*100);
        appetite = correctRange("appetiteScore", appetite);

        return appetite;
    }

    /**
     * @return 1 / size^3
     */
    protected double countReproductionScore()
    {
        AnimalGene gene = (AnimalGene) getGenotype();

        double size = gene.getGene(AnimalGene.SIZE_GENE);
        double muscle = gene.getGene(AnimalGene.MUSCLE_GENE);
        
        double reproduction = 4.0 - size / 25.0 - muscle / 25.0;

        /* normalizacja */
        reproduction = normalize(reproduction, 0.01, 1);
        reproduction = correctRange("reproductionScore",reproduction);

        return reproduction;
    }

    protected double normalize(double paramValue, double minValue, double maxValue)
    {
         /* double ret = paramValue / (maxValue - minValue) * 100 + 1;
          return (int) ret;*/
        return paramValue;
    }

    protected double correctRange(String paramName, double paramValue)
    {
//        if(paramValue < 1)
//        {
//            // System.out.println("Warning: parameter " + paramName +" range has been corrected, original value=" + paramValue);
//            return 1;
//        }
//        else if(paramValue > 100)
//        {
//            if(paramValue > 150)
//                System.out.println("Warning: parameter " + paramName +" range has been corrected, original value=" + paramValue);
//            return 100;
//        }
//        else
//            return (int) paramValue;
        return paramValue;
    }

    public double getHuntingScore() {
        return huntingScore;
    }

    public double getAppetiteScore() {
        return appetiteScore;
    }

    public double getReproductionScore() {
        return reproductionScore;
    }

}
